!function($) {
    /* 基于Bootstrap Typeahead改造而来的自动完成插件
     * Author：F.L.F
     * Site: http://digdata.me
     * ================================= */

    var Autocomplete = function(element, options) {
        this.$element = $(element)
        this.options = $.extend({}, $.fn.autocomplete.defaults, options)
        this.sorter = this.options.sorter || this.sorter
        this.highlighter = this.options.highlighter || this.highlighter
        this.updater = this.options.updater || this.updater
        this.source = this.options.source
        this.$menu = $(this.options.menu)
        this.shown = false
        this.searchAttr=this.options.searchAttr
        this.formatItem = this.options.formatItem || this.formatItem
        this.setValue = this.options.setValue || this.setValue
        this.select = this.options.select || this.select
        this.listen()
    }

    Autocomplete.prototype = {
        constructor: Autocomplete
        ,
        processObj: 0
        ,
        formatItem: function(item) {
            return item.toString();
        }
        ,
        setValue: function(item) {
            return {
                "data-value": item.toString(),
                "real-value": item.toString()
            };
        }

        ,
        select: function() {
            var val = this.$menu.find('.active').attr('data-value')
            var realVal = this.$menu.find('.active').attr('real-value')
            this.$element
                    .val(this.updater(val)).attr("real-value", realVal)
                    .change()
            return this.hide()
        }

        ,
        updater: function(item) {
            return item
        }

        ,
        show: function() {
            var pos = $.extend({}, this.$element.position(), {
                height: this.$element[0].offsetHeight
            })
            
            
            this.$menu
                    .insertAfter(this.$element)
                    .css({
//                        bottom:$(window).height()-pos.top
                        top: pos.top + pos.height
                        ,
                        left: pos.left
                    })
                    
            var that=this;
            setTimeout(function(){
                var w_height = $(window).height();
                var w_top = pos.top;
                var content_height = that.$menu.height();
                if(w_height-w_top<150){
                    
                    that.$menu.css("top",w_top-content_height);
                }
                that.$menu.show();
               
            },100)
            this.shown = true;
            return this;
        }

        ,
        hide: function() {
            this.$menu.hide()
            this.shown = false
            return this
        }

        ,
        lookup: function(event) {
            var items;
           // console.log(this.searchAttr+"---222222222222----");
            if(this.searchAttr){
                  this.query = this.$element.attr(this.searchAttr);
                 // console.log(this.$element.attr(this.searchAttr));
            }else{
                this.query = this.$element.val();
            }
            
            if (this.options.focusSearch) {

            } else {
                if (!this.query || this.query.length < this.options.minLength) {
                    return this.shown ? this.hide() : this
                }
            }

            // alert(123);
            items = $.isFunction(this.source) ? this.source(this.query, $.proxy(this.process, this)) : this.source

            return items ? this.process(items) : this
        }

        ,
        process: function(items) {
            var that = this
            if (!items.length) {
                return this.shown ? this.hide() : this
            }

            return this.render(items.slice(0, this.options.items)).show();
            
        }

        ,
        highlighter: function(item) {
            var that = this
            item = that.formatItem(item)
            return item;
            //      var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&')
            //      return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) {
            //        return '<strong style="color:#FF6600;">' + match + '</strong>'
            //      })
        }

        ,
        render: function(items) {
            var that = this

            items = $(items).map(function(i, item) {
                i = $(that.options.item).attr(that.setValue(item))
                //alert(that.highlighter(item));
                i.html(that.highlighter(item))
                return i[0]
            })

            items.first().addClass('active')
            this.$menu.html(that.options.thisHtml);
           
            this.$menu.append(items);
             console.log(items.length+"--------------"+this.$menu.height()+"-----");
            return this
        }

        ,
        next: function(event) {
            var active = this.$menu.find('.active').removeClass('active')
                    , next = active.next()

            if (!next.length) {
                next = $(this.$menu.find('li')[0])
            }

            next.addClass('active')
        }

        ,
        prev: function(event) {
            var active = this.$menu.find('.active').removeClass('active')
                    , prev = active.prev()

            if (!prev.length) {
                prev = this.$menu.find('li').last()
            }

            prev.addClass('active')
        }

        ,
        listen: function() {
            this.$element
                    .on('focus', $.proxy(this.focus, this))
                    .on('blur', $.proxy(this.blur, this))
                    .on('keypress', $.proxy(this.keypress, this))
                    .on('keyup', $.proxy(this.keyup, this))
             .on('click', $.proxy(this.myclick, this))

            if (this.eventSupported('keydown')) {
                this.$element.on('keydown', $.proxy(this.keydown, this))
            }

            this.$menu
                    .on('click', $.proxy(this.click, this))
                    .on('mouseenter', 'tr', $.proxy(this.mouseenter, this))
                    .on('mouseleave', 'tr', $.proxy(this.mouseleave, this))
            //        .on('mouseenter', 'li', $.proxy(this.mouseenter, this))
            //        .on('mouseleave', 'li', $.proxy(this.mouseleave, this))
        }

        ,
        eventSupported: function(eventName) {
            var isSupported = eventName in this.$element
            if (!isSupported) {
                this.$element.setAttribute(eventName, 'return;')
                isSupported = typeof this.$element[eventName] === 'function'
            }
            return isSupported
        }

        ,
        move: function(e) {
            if (!this.shown)
                return

            switch (e.keyCode) {
                case 9: // tab
                case 13: // enter
                case 27: // escape
                    e.preventDefault()
                    break

                case 38: // up arrow
                    e.preventDefault()
                    this.prev()
                    break

                case 40: // down arrow
                    e.preventDefault()
                    this.next()
                    break
            }

            e.stopPropagation()
        }

        ,
        keydown: function(e) {
            this.suppressKeyPressRepeat = ~$.inArray(e.keyCode, [40, 38, 9, 13, 27])
            this.move(e)
        }

        ,
        keypress: function(e) {
            if (this.suppressKeyPressRepeat)
                return
            this.move(e)
        }

        ,
        keyup: function(e) {
            switch (e.keyCode) {
                case 40: // down arrow
                case 38: // up arrow
                case 16: // shift
                case 17: // ctrl
                case 18: // alt
                    break

                case 9: // tab
                case 13: // enter
                    if (!this.shown)
                        return
                    this.select()
                    break

                case 27: // escape
                    if (!this.shown)
                        return
                    this.hide()
                    break

                default:
                    var that = this
                    that.options.focusSearch2 = true;
                    if (that.processObj) {
                        clearTimeout(that.processObj)
                        that.processObj = 0
                    }
                    that.processObj = setTimeout(function() {
                        that.lookup()
                    }, that.options.delay)
            }

            e.stopPropagation()
            e.preventDefault()
        }

        ,
        focus: function(e) {
            this.focused = true
            var that = this
            if (that.options.focusSearch) {
                if (that.options.focusSearch2) {
                    if (that.processObj) {
                        clearTimeout(that.processObj)
                        that.processObj = 0
                    }
                    that.processObj = setTimeout(function() {
                        that.lookup()
                    }, that.options.delay)
                }

            }
        },
        
          myclick: function(e) {
            
            var that = this
            if (that.options.clickSearch) {
              
                    if (that.processObj) {
                        clearTimeout(that.processObj)
                        that.processObj = 0
                    }
                    that.processObj = setTimeout(function() {
                        that.lookup()
                    }, that.options.delay)
                

            }
        }

        ,
        blur: function(e) {
            this.focused = false
            if (!this.mousedover && this.shown)
                this.hide()
        }

        ,
        click: function(e) {
            e.stopPropagation()
            e.preventDefault()
            this.select()
            this.options.focusSearch2 = false;
            this.$element.focus();

        }

        ,
        mouseenter: function(e) {
            this.mousedover = true
            this.$menu.find('.active').removeClass('active')
            $(e.currentTarget).addClass('active')
        }

        ,
        mouseleave: function(e) {
            this.mousedover = false
            if (!this.focused && this.shown)
                this.hide()
        }

    }


    /* TYPEAHEAD PLUGIN DEFINITION
     * =========================== */

    var old = $.fn.autocomplete

    $.fn.autocomplete = function(option) {
        //console.log(option);
        return this.each(function() {
            var $this = $(this)
                    , data = $this.data('autocomplete')
                    , options = typeof option == 'object' && option
            if (!data)
                $this.data('autocomplete', (data = new Autocomplete(this, options)))
            if (typeof option == 'string')
                data[option]()
        })
    }

    $.fn.autocomplete.defaults = {
        source: []
        ,
        items: 8
        ,
        menu: '<ul class="typeahead dropdown-menu"></ul>'
        ,
        item: '<li><a href="#"></a></li>'
        ,
        thisHtml: ""
        ,
        focusSearch: true
        ,
        focusSearch2: true
        ,
        minLength: 1
        ,
        delay: 500
    }

    $.fn.autocomplete.Constructor = Autocomplete


    /* TYPEAHEAD NO CONFLICT
     * =================== */

    $.fn.autocomplete.noConflict = function() {
        $.fn.autocomplete = old;
        return this
    }


    /* TYPEAHEAD DATA-API
     * ================== */

    $(document).on('focus.autocomplete.data-api', '[data-provide="autocomplete"]', function(e) {
        var $this = $(this)
       // console.log("focus");
        if ($this.data('autocomplete'))
            return
        $this.autocomplete($this.data())
    })

}(window.jQuery);